
package todolist.logic.reminder;

import java.util.ArrayList;
import java.util.Date;
import java.util.Timer;
import java.util.TimerTask;
import javax.swing.JOptionPane;
import todolist.entity.TaskEntity;
import todolist.personalization.DateTimeDescriptionCustomizer;
import todolist.util.DateUtils;
import todolist.util.TTS;
import todolist.util.Utils;

/**
 * Controller facade for Reminder scheduling subsystem, Singleton class.
 * @author YouLi
 * @author Ivan
 */
public class ReminderController implements ReminderTaskChangedListener {
	
	// handle singleton instance

	private static ReminderController _objRC;

	public static ReminderController getInstance() {
		if (_objRC == null)
			_objRC = new ReminderController();
		return _objRC;
	}

	private Timer _tmrReminder;
	private TaskEntity _entRemindingTask;
	private TTS _objTTS;
	
	private ArrayList<ReminderExpiredListener> _objREList; // listener
	
	private ReminderController() {
		_tmrReminder = null;
		_entRemindingTask = null;
		_objREList = new ArrayList<ReminderExpiredListener>();
		_objTTS = TTS.getInstance();
	}
	
	// listener methods
	
	public void addReminderExpiredListener(ReminderExpiredListener pobjREListener) {
		_objREList.add(pobjREListener);
	}
	
	public boolean removeReminderExpiredListener(ReminderExpiredListener pobjREListener) {
		return _objREList.remove(pobjREListener);
	}
	
	private class Reminder extends TimerTask {
		
		@Override
	    public void run() {
	    	_objTTS.say("Reminder");
	    	_objTTS.say(_entRemindingTask.getTaskName());
	    	_objTTS.say(DateTimeDescriptionCustomizer.getInstance().getDTDisplayOneEndDate());
	    	_objTTS.say(_entRemindingTask.getEndDT().toVoiceFriendlyString());
	    	JOptionPane.showMessageDialog(null,
		    	_entRemindingTask.getTaskName() + Utils.getLineSeparator() +
		    	DateTimeDescriptionCustomizer.getInstance().getDTDisplayOneEndDate() + " " +
		    	_entRemindingTask.getEndDT().toString(),
		   		"To-Do-List Reminder", JOptionPane.WARNING_MESSAGE, null);
	    	// notify listeners
	    	for (ReminderExpiredListener objREListener : _objREList)
	    		objREListener.reminderExpired();
	    }
	}
	
	// listener implementation methods

	/**
	 * Perform comparison before scheduling an earlier Task by Reminder Date.
	 */
	@Override
	public void reminderTaskMayHaveChanged(TaskEntity pentIncomingTask) {
		assert pentIncomingTask != null;
		Date dtmNow = DateUtils.removeSecondsFromDate(new Date());
		if (pentIncomingTask.getReminderDate() == null ||
			pentIncomingTask.getReminderDate().before(dtmNow))
			return;
		if (_entRemindingTask == null)
			reminderTaskForceChanged(pentIncomingTask);
		assert pentIncomingTask.getReminderDate() != null;
		// at this point, there are 2 tasks, both with Reminder Dates after current Date/Time
		if (pentIncomingTask.getReminderDate().before(_entRemindingTask.getReminderDate()) &&
			pentIncomingTask.getReminderDate().after(dtmNow)) // initiate comparison
			reminderTaskForceChanged(pentIncomingTask);
	}

	/**
	 * Schedules/unschedules task to be reminded.
	 */
	@Override
	public void reminderTaskForceChanged(TaskEntity pentIncomingTask) {
		unschedule();
		if (pentIncomingTask == null)
			return;
		assert pentIncomingTask.getReminderDate() != null;
		_entRemindingTask = pentIncomingTask;
		_tmrReminder = new Timer();
		_tmrReminder.schedule(new Reminder(), pentIncomingTask.getReminderDate());
	}
	
	// private methods
	
	/**
	 * Unschedules task when there is no reminder.
	 */
	private void unschedule() {
		if (_tmrReminder != null) {
			_tmrReminder.cancel();
			_tmrReminder = null;
			_entRemindingTask = null;
		}
	}
	
}
